<?php
namespace TennisTournament\Service;

use Doctrine\Common\Collections\Collection;
use TennisTournament\Model\Group;
use TennisTournament\Model\GroupStats;
use TennisTournament\Persistent\GroupDao;
use TennisTournament\Service\PlayerService;

use Zend\Json\Json;

class GroupServiceImpl implements GroupService {

    /** @var GroupDao */
    protected $groupDao;

    /** @var PlayerService */
    protected $playerService;

    /** @var CommonService */
    protected $commonService;

    /**
     * @param GroupDao $groupDao
     * @param PlayerService $playerService
     * @param CommonService $commonService
     */
    public function __construct(GroupDao $groupDao, PlayerService $playerService, CommonService $commonService) {
        $this->groupDao = $groupDao;
        $this->playerService = $playerService;
        $this->commonService = $commonService;
    }

    /**
     * Get an {@link Group} entity by its {@link $id}
     * @param $id integer
     * @return Group if have an entity with such id or null otherwise
     * @throws \Exception
     */
    public function get($id) {
        $this->groupDao->startTransaction();
        try {
            /** @var $group Group */
            $group = $this->groupDao->get($id);

            $this->groupDao->commitTransaction();

            return $group;
        } catch(\Exception $ex) {
            $this->groupDao->rollbackTransaction();
            throw $ex;
        }
    }

    /**
     * Get all {@link Group} entities
     * @return Array from all {@link Group}
     * @throws \Exception
     */
    public function fetchAll() {
        $this->groupDao->startTransaction();
        try {
            /** @var $groups array from Group */
            $groups = $this->groupDao->fetchAll();

            $this->groupDao->commitTransaction();

            return $groups;
        } catch (\Exception $ex) {
            $this->groupDao->rollbackTransaction();
            throw $ex;
        }
    }

    /**
     * Save an specific entity;
     * @param $entity Group
     * @return void
     * @throws \Exception
     */
    public function save($entity) {
        $this->groupDao->startTransaction();
        try {
            $collectionGroupStats = $entity->getStats();
            /** @var $groupStats GroupStats */
            foreach ($collectionGroupStats as $groupStats) {
                $player = $groupStats->getPlayer();
                $player = $this->playerService->get($player->getId());
                $groupStats->setPlayer($player);
            }

            $entity->setStats($collectionGroupStats);

            $this->groupDao->save($entity);

            $this->groupDao->commitTransaction();
        } catch (\Exception $ex) {
            $this->groupDao->rollbackTransaction();
            throw $ex;
        }
    }

    /**
     * Delete an specific entity;
     * @param entity
     * @return void
     * @throws \Exception
     */
    public function delete($entity) {
        $this->groupDao->startTransaction();
        try {
            $this->groupDao->delete($entity);

            $this->groupDao->commitTransaction();
        } catch (\Exception $ex) {
            $this->groupDao->rollbackTransaction();
            throw $ex;
        }
    }

    /**
     * Encode Group to JSON object
     * @param Group $group
     * @return string
     */
    public function toJSON(Group $group) {
       return Json::encode(
           $group->toArray()
        );
    }


    /**
     * Get all groups
     * @return array
     */
    public function listAll() {
        $collectionGroups =  $this->groupDao->fetchAll();
        /** @var $group Group */
        foreach ($collectionGroups as $group) {
            /** @var $stats Collection */
            $stats = $group->getStats();
            $group->setStats($stats->toArray());
        }

        return $collectionGroups;
    }

    /*
     * Get all groups with sorted {@link GroupStats} into there.</br>
     * First will be sort the {@Player} with most points.</br>
     * After this will be sort the {@Player} with most positive difference,
     * between takenPoints and getPoints.
     * if is not defined will set the array from listAll() for $collectionGroups
     * @return array
     */
    public function getAllGroupsSorted(array $collectionGroups = array()) {
        if (count($collectionGroups) == 0) {
            $collectionGroups = $this->listAll();
        }

        /** @var $group Group */
        foreach ($collectionGroups as $group) {
            $this->commonService->sortGroupStats($group);
        }

        return $collectionGroups;
    }

    /**
     * Return, whether the number of groups are eligible for tournament logic
     * @param $intNumberGroups integer
     * @return boolean
     */
    public function isEligibleNumberOfGroups($intNumberGroups) {
        switch($intNumberGroups) {
            case GroupService::ELIGIBLE_NUMBER_GROUPS_ONE :
            case GroupService::ELIGIBLE_NUMBER_GROUPS_TWO :
            case GroupService::ELIGIBLE_NUMBER_GROUPS_FOUR :
            case GroupService::ELIGIBLE_NUMBER_GROUPS_EIGHT :
                return true;
            default:
                return false;
        }
    }

}